package com.camel.iamfx.index;

import com.camel.iamfx.FxUtil;
import com.camel.iamfx.config.SystemConfig;
import com.camel.iamfx.model.PluginJarInfo;
import com.camel.iamfx.model.ToolFxmlLoaderConfiguration;
import com.camel.iamfx.utils.PluginLoader;
import com.camel.iamfx.utils.PluginManager;
import com.xwintop.xcore.javafx.dialog.FxAlerts;
import com.xwintop.xcore.util.javafx.TooltipUtil;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ResourceUtils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.URL;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

@Slf4j
public class Controller implements Initializable {

    private Map<String, Menu> menuMap = new HashMap<>();

    protected ResourceBundle bundle;

    private Map<String, MenuItem> menuItemMap = new HashMap<>();

    private Map<String, ToolFxmlLoaderConfiguration> toolFxmlLoaderConfigurations = new HashMap<>();

    @FXML
    private TabPane homePane;

    @FXML
    private GridPane myAppGridPane;

    @FXML
    private Button btnPluginRefresh;

    /**
     * 手动刷新界面
     * @param event
     */
    @FXML
    void refreshPlugin(ActionEvent event) {
        this.doInit();
    }

    @FXML
    void openPluginMarketTag(ActionEvent event) {
        Tab tab = new Tab();
        try {
            Pane load = FXMLLoader.load(Objects.requireNonNull(getClass().getResource("/fxml/market.fxml")));
            tab.setContent(load);
            tab.setText("插件市场");
            addNewTab(tab, homePane);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @FXML
    void addInclude() {
        Tab tab = new Tab();
        try {
            Pane load = FXMLLoader.load(Objects.requireNonNull(getClass().getResource("/fxml/market.fxml")));
            tab.setContent(load);
            tab.setText("引入");
            addNewTab(tab, homePane);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        this.bundle = resources;
        this.doInit();
    }

    private void doInit() {
        this.menuItemMap.clear();
        this.menuMap.clear();
        try {
            String folder = "libs/";
            File file = new File(folder);
            if(!file.exists()) {
                file.mkdir();
            } else {
                File[] files = file.listFiles((dir, name) -> name.endsWith(".jar"));
                for (File f : files) {
                    try {
                        FxUtil.addJarClass(f);
                    } catch (Exception e) {
                        log.error("加载JAR包出错：", e);
                    }
                }

                for (File f : files) {
                    try {
                        this.addToolMenu(f);
                    } catch (Exception e) {
                        log.error("加载工具出错：", e);
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        this.initAppPane();
    }

    private void initAppPane() {
        myAppGridPane.getChildren().clear();
        Integer index = 0;
        for (String s : menuItemMap.keySet()) {
            MenuItem menuItem = menuItemMap.get(s);
            ImageView imageView = new ImageView();
            if(!ObjectUtils.isEmpty(menuItem.getGraphic())) {
                ImageView view = (ImageView) menuItem.getGraphic();
                Image image = view.getImage();
                imageView.setImage(image);
            }
            imageView.setFitHeight(80);
            imageView.setFitWidth(80);

            Label nameLabel = new Label(s);
            Label versionLabel = new Label("版本: " + "0.0.1 ");
            HBox hBox = new HBox();
            hBox.getChildren().add(imageView);
            VBox pane = new VBox();
            pane.getChildren().add(nameLabel);
            pane.getChildren().add(versionLabel);
            hBox.getChildren().add(pane);
            hBox.setOnMouseClicked(event -> {
                TooltipUtil.showToast(s);
                ToolFxmlLoaderConfiguration configuration = toolFxmlLoaderConfigurations.get(s);
                PluginJarInfo pluginJarInfo = PluginManager.getInstance().getPluginByFxmlPath(configuration.getUrl());
                if (pluginJarInfo == null) {
                    FxAlerts.error("打开失败", "没有找到指定的插件");
                    return;
                }
                PluginLoader.loadPluginAsTab(pluginJarInfo, homePane);
            });
            hBox.setPadding(new Insets(22));
            myAppGridPane.add(hBox, index % SystemConfig.HOME_APP_LINE_NUM, index/SystemConfig.HOME_APP_LINE_NUM);
            index++;
        }
//        myAppGridPane.setGridLinesVisible(true);
    }

    /**
     * 给pane添加新的标签
     * @param nTab
     * @param pane
     */
    private void addNewTab(Tab nTab, TabPane pane) {
        ObservableList<Tab> tabs = pane.getTabs();
        for (Tab tab : tabs) {
            String s = tab.getText();
            if(s.equals(nTab.getText())) {
                // 选中
                return;
            }
        }
        // 创建新标签
        tabs.add(nTab);
        pane.getSelectionModel().select(nTab);
    }

    public void addToolMenu(File file) throws Exception {
        Map<String, ToolFxmlLoaderConfiguration> toolMap = new HashMap<>();
        List<ToolFxmlLoaderConfiguration> toolList = new ArrayList<>();
        try (JarFile jarFile = new JarFile(file)) {
            JarEntry entry = jarFile.getJarEntry("config/toolFxmlLoaderConfiguration.xml");
            if (entry == null) {
                return;
            }
            InputStream input = jarFile.getInputStream(entry);
            SAXReader saxReader = new SAXReader();
            Document document = saxReader.read(input);
            Element root = document.getRootElement();
            List<Element> elements = root.elements("ToolFxmlLoaderConfiguration");
            for (Element configurationNode : elements) {
                ToolFxmlLoaderConfiguration toolFxmlLoaderConfiguration = new ToolFxmlLoaderConfiguration();
                List<Attribute> attributes = configurationNode.attributes();
                for (Attribute configuration : attributes) {
                    BeanUtils.copyProperty(toolFxmlLoaderConfiguration, configuration.getName(), configuration.getValue());
                }
                List<Element> childrenList = configurationNode.elements();
                for (Element configuration : childrenList) {
                    BeanUtils.copyProperty(toolFxmlLoaderConfiguration, configuration.getName(), configuration.getStringValue());
                }
                if (StringUtils.isEmpty(toolFxmlLoaderConfiguration.getMenuParentId())) {
                    toolFxmlLoaderConfiguration.setMenuParentId("moreToolsMenu");
                }
                if (toolFxmlLoaderConfiguration.getIsMenu()) {
                    if (menuMap.get(toolFxmlLoaderConfiguration.getMenuId()) == null) {
                        toolMap.putIfAbsent(toolFxmlLoaderConfiguration.getMenuId(), toolFxmlLoaderConfiguration);
                    }
                } else {
                    toolList.add(toolFxmlLoaderConfiguration);
                }
            }

        }
        toolList.addAll(toolMap.values());
        this.addMenu(toolList);
    }

    private void addMenu(List<ToolFxmlLoaderConfiguration> toolList) {
        for (ToolFxmlLoaderConfiguration toolConfig : toolList) {
            try {
                if (StringUtils.isEmpty(toolConfig.getResourceBundleName())) {
//                    if (StringUtils.isNotEmpty(bundle.getString(toolConfig.getTitle()))) {
//                        toolConfig.setTitle(bundle.getString(toolConfig.getTitle()));
//                    }
                } else {
                    bundle = ResourceBundle.getBundle(toolConfig.getResourceBundleName(), Locale.getDefault());
                    if (StringUtils.isNotEmpty(bundle.getString(toolConfig.getTitle()))) {
                        toolConfig.setTitle(bundle.getString(toolConfig.getTitle()));
                    }
                }
            } catch (Exception e) {
                log.error("加载菜单失败", e);
            }
            if (toolConfig.getIsMenu()) {
                Menu menu = new Menu(toolConfig.getTitle());
                if (StringUtils.isNotEmpty(toolConfig.getIconPath())) {
                    ImageView imageView = new ImageView(new Image(toolConfig.getIconPath()));
                    imageView.setFitHeight(18);
                    imageView.setFitWidth(18);
                    menu.setGraphic(imageView);
                }
                menuMap.put(toolConfig.getMenuId(), menu);
            }
        }

        for (ToolFxmlLoaderConfiguration toolConfig : toolList) {
            if (toolConfig.getIsMenu()) {
                continue;
            }
            MenuItem menuItem = new MenuItem(toolConfig.getTitle());
            if (StringUtils.isNotEmpty(toolConfig.getIconPath())) {
                ImageView imageView = new ImageView(new Image(toolConfig.getIconPath()));
                imageView.setFitHeight(18);
                imageView.setFitWidth(18);
                menuItem.setGraphic(imageView);
            }
            if ("Node".equals(toolConfig.getControllerType())) {
                menuItem.setOnAction((ActionEvent event) -> {
                    TooltipUtil.showToast("操作1");
                });
                if (toolConfig.getIsDefaultShow()) {
                    TooltipUtil.showToast("操作2");
                }
            } else if ("WebView".equals(toolConfig.getControllerType())) {
                menuItem.setOnAction((ActionEvent event) -> {
                    TooltipUtil.showToast("操作3");
                });
                if (toolConfig.getIsDefaultShow()) {
                    TooltipUtil.showToast("操作4");
                }
            }
            menuMap.get(toolConfig.getMenuParentId()).getItems().add(menuItem);
            menuItemMap.put(menuItem.getText(), menuItem);
            toolFxmlLoaderConfigurations.put(menuItem.getText(), toolConfig);
        }
    }
}
